﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace GroundStation
{
  class ArtificialHorizon
  {
    BufferedGraphicsContext context = BufferedGraphicsManager.Current;
    BufferedGraphics buffer = null;
    Graphics gr;
    int width = 0;
    int height = 0;

    Pen whitePen = new Pen(Color.White, 1);
    Pen whitePenBold = new Pen(Color.White, 3);
    SolidBrush whiteBrush = new SolidBrush(Color.White);
    SolidBrush blueBrush = new SolidBrush(Color.FromArgb(255, 28, 134, 186));
    SolidBrush brownBrush = new SolidBrush(Color.FromArgb(255, 219, 140, 21));
    Font font = new Font("Arial", 8);
    Point[] ptGround = new Point[4];
    Point[] ptSky = new Point[4];
    Point[] pt = new Point[2];
    Point[] ptW = new Point[7];
    Point[] ptArrow = new Point[3];

    float lastRoll = 0xFF00;
    float lastPitch = 0xFF00;

    /// <summary>
    /// Initializes indicator
    /// </summary>
    /// <param name="pictureBox">Picturebox.</param>
    public void Init(PictureBox pictureBox)
    {
      buffer = context.Allocate(pictureBox.CreateGraphics(), pictureBox.DisplayRectangle);
      buffer.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
      gr = buffer.Graphics;

      width = pictureBox.Width;
      height = pictureBox.Height;
      Draw(20, 15, 147, 240, 11);
    }

    /// <summary>
    /// Draw indicator with parameter
    /// </summary>
    /// <param name="roll">Roll angle.</param>
    /// /// <param name="pitch">Pitch angle.</param>
    public void Draw(float pitch, float roll, float heading, float speed, float altitude)
    {
      if (Math.Abs(pitch) > 120 || Math.Abs(roll) > 200 || heading > 360 || heading < 0)
      {
        return;
      }

      // if changed
      if (lastRoll != roll || lastPitch != pitch)
      {
        gr.Clear(Color.Black);

        ptSky[0].X = -400;
        ptSky[0].Y = -1200;
        ptSky[1].X = 4;
        ptSky[1].Y = -1200;
        ptSky[2].X = 400;
        ptSky[2].Y = 0;
        ptSky[3].X = -400;
        ptSky[3].Y = 0;

        ptGround[0].X = -400;
        ptGround[0].Y = 0;
        ptGround[1].X = 400;
        ptGround[1].Y = 0;
        ptGround[2].X = 400;
        ptGround[2].Y = 1200;
        ptGround[3].X = -400;
        ptGround[3].Y = 1200;

        gr.TranslateTransform(width / 2, height / 2);
        gr.RotateTransform(-roll);
        gr.TranslateTransform(0, pitch * 4);

        // ground and sky
        gr.FillPolygon(blueBrush, ptSky);
        gr.FillPolygon(brownBrush, ptGround);
        gr.DrawLine(whitePen, ptGround[0], ptGround[1]);

        // pitch scale
        for (int i = -90; i <= 90; i += 5)
        {
          if (i != 0 && i <= -pitch + 20 && i >= -pitch - 20)
          {
            if (i % 10 == 0)
            {
              pt[0].X = -40;
              pt[0].Y = (int)(i * 4);
              pt[1].X = 40;
              pt[1].Y = (int)(i * 4);
              gr.DrawLine(whitePen, pt[0], pt[1]);
              pt[1].X += 3;
              pt[1].Y -= 6;
              gr.DrawString(Math.Abs(i).ToString(), font, whiteBrush, pt[1]);
              pt[1].X -= 100;
              gr.DrawString(Math.Abs(i).ToString(), font, whiteBrush, pt[1]);
            }
            else
            {
              pt[0].X = -15;
              pt[0].Y = (int)(i * 4);
              pt[1].X = 15;
              pt[1].Y = (int)(i * 4);
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
          }
        }

        // roll arrow
        if (roll <= 45 && roll >= -45)
        {
          ptArrow[0].X = -10;
          ptArrow[0].Y = (int)(-pitch * 4 + 115);
          ptArrow[1].X = 10;
          ptArrow[1].Y = (int)(-pitch * 4 + 115);
          ptArrow[2].X = 0;
          ptArrow[2].Y = (int)(-pitch * 4 + 130);

          gr.FillPolygon(whiteBrush, ptArrow);
        }

        gr.ResetTransform();

        // -w-
        ptW[0].X = width / 2 - 40;
        ptW[0].Y = height / 2;
        ptW[1].X = width / 2 - 20;
        ptW[1].Y = height / 2;
        ptW[2].X = width / 2 - 10;
        ptW[2].Y = height / 2 + 10;
        ptW[3].X = width / 2 + 0;
        ptW[3].Y = height / 2;
        ptW[4].X = width / 2 + 10;
        ptW[4].Y = height / 2 + 10;
        ptW[5].X = width / 2 + 20;
        ptW[5].Y = height / 2;
        ptW[6].X = width / 2 + 40;
        ptW[6].Y = height / 2;
        gr.DrawLines(whitePenBold, ptW);

        // roll scale
        for (int i = -45; i <= 45; i += 5)
        {
          if (i == 0)
          {
            pt[0].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 125);
            pt[0].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 125);
            pt[1].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 140);
            pt[1].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 140);
            gr.DrawLine(whitePen, pt[0], pt[1]);
          }
          else if (i % 10 == 0)
          {
            pt[0].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 130);
            pt[0].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 130);
            pt[1].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 140);
            pt[1].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 140);
            gr.DrawLine(whitePen, pt[0], pt[1]);
          }
          else
          {
            pt[0].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 135);
            pt[0].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 135);
            pt[1].X = (int)(width / 2 + Math.Cos((i + 90) * 0.0174) * 140);
            pt[1].Y = (int)(height / 2 + Math.Sin((i + 90) * 0.0174) * 140);
            gr.DrawLine(whitePen, pt[0], pt[1]);
          }
        }

        for (int i = 0; i <= 150; i++)
        {
          string str;

          if (i < speed + 30.0f && i > speed - 30.0f)
          {
            str = i.ToString();

            if (i % 5 == 0)
            {
              pt[0].X = 22;
              pt[0].Y = height / 2 + (int)(speed - i) * 5 - 6;
              gr.DrawString(str, font, whiteBrush, pt[0]);

              pt[0].X = 10;
              pt[0].Y = height / 2 + (int)(speed - i) * 5;
              pt[1].X = 20;
              pt[1].Y = height / 2 + (int)(speed - i) * 5;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
            else
            {
              pt[0].X = 10;
              pt[0].Y = height / 2 + (int)(speed - i) * 5;
              pt[1].X = 15;
              pt[1].Y = height / 2 + (int)(speed - i) * 5;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
          }
        }

        ptArrow[0].X = 65;
        ptArrow[0].Y = height / 2 - 10;
        ptArrow[1].X = 65;
        ptArrow[1].Y = height / 2 + 10;
        ptArrow[2].X = 50;
        ptArrow[2].Y = height / 2;
        gr.FillPolygon(whiteBrush, ptArrow);

        for (int i = 0; i <= 3000; i++)
        {
          string str;

          if (i < altitude + 30.0f && i > altitude - 30.0f)
          {
            str = i.ToString();

            if (i % 10 == 0)
            {
              pt[0].X = width - 31 - str.Length * 4;
              pt[0].Y = height / 2 + (int)(altitude - i) * 5 - 6;
              gr.DrawString(str, font, whiteBrush, pt[0]);

              pt[0].X = width - 10;
              pt[0].Y = height / 2 + (int)(altitude - i) * 5;
              pt[1].X = width - 20;
              pt[1].Y = height / 2 + (int)(altitude - i) * 5;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
            else
            {
              pt[0].X = width - 10;
              pt[0].Y = height / 2 + (int)(altitude - i) * 5;
              pt[1].X = width - 15;
              pt[1].Y = height / 2 + (int)(altitude - i) * 5;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
          }
        }

        ptArrow[0].X = width - 65;
        ptArrow[0].Y = height / 2 - 10;
        ptArrow[1].X = width - 65;
        ptArrow[1].Y = height / 2 + 10;
        ptArrow[2].X = width - 50;
        ptArrow[2].Y = height / 2;
        gr.FillPolygon(whiteBrush, ptArrow);

        // compass
        for (int i = -60; i <= 420; i += 2)
        {
          string str;

          if (i < heading + 20.0f && i > heading - 20.0f)
          {
            if (i < 0)
              str = Math.Abs(360 + i).ToString();
            else if (i >= 360)
              str = Math.Abs(i - 360).ToString();
            else
              str = Math.Abs(i).ToString();

            if (i % 10 == 0)
            {
              pt[0].X = width / 2 + 5 * (int)(i - heading) - 3 * str.Length;
              pt[0].Y = 5;
              gr.DrawString(str, font, whiteBrush, pt[0]);

              pt[0].X = width / 2 + 5 * (int)(i - heading);
              pt[0].Y = 20;
              pt[1].X = width / 2 + 5 * (int)(i - heading);
              pt[1].Y = 30;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
            else
            {
              pt[0].X = width / 2 + 5 * (int)(i - heading);
              pt[0].Y = 25;
              pt[1].X = width / 2 + 5 * (int)(i - heading);
              pt[1].Y = 30;
              gr.DrawLine(whitePen, pt[0], pt[1]);
            }
          }
        }
        ptArrow[0].X = width / 2 - 10;
        ptArrow[0].Y = 45;
        ptArrow[1].X = width / 2 + 10;
        ptArrow[1].Y = 45;
        ptArrow[2].X = width / 2;
        ptArrow[2].Y = 30;
        gr.FillPolygon(whiteBrush, ptArrow);
      }

      lastRoll = roll;
      lastPitch = pitch;
      // draw
      if( buffer != null) buffer.Render();
    }
  }
}
